package su2010.puz.extractors;

import java.awt.image.BufferedImage;

import su2010.puz.Extractor;
import su2010.puz.Filter;
import su2010.puz.util.ImageCls;
import su2010.puz.util.PixelExtractor;

/**
 * Extractor that gives a measure of symmetry in an image.
 * Worthless.
 * @author Bruno
 *
 */
public class SymmetryExtractor implements Extractor{

	private BufferedImage image;
	private int division = 1;
	private Filter[] filters = null;
	
	/**
	 * Main constructor.
	 * @param division Number of divisions into the image.
	 * @param filters Filters to be applyed before extraction.
	 */
	public SymmetryExtractor(int division, Filter ... filters){
		this.division = division;
		this.filters = filters;
	}
	public SymmetryExtractor() {		
	}
	
	/**
	 * Divides image into number of subfields, determined by division
	 * parameter. It then performs subtraction of right side of subimage
	 * from left side of subimage and bottom from top.
	 * Returns array of floats, each number represents how symmetrical
	 * images in subdivision are. Lower is more symmetrical.
	 */
	@Override
	public float[] extract() {
		float[] out = new float[division];
		
		if(filters!=null)
			for(Filter filter : filters)
				image = filter.apply(image);
		
		int height = image.getHeight();
		int width = image.getWidth();
		int[] pixels = new int[height*width];		
		PixelExtractor.getRGB(image, 0, 0, width, height, pixels);
		
		double tmp = 0.0f;
		float squareSum = 0.0f;
		for(int d = 1; d<=division; d++){
			out[d-1] = 0.0f;
			int horisontal = width/d;
			int vertical = height/d;		
			for(int hd=0; hd<d; hd++){
				for(int i=hd*horisontal; i<(hd+0.5f)*horisontal; i++){
					for(int j=0; j<height; j++){
						tmp = pixels[j*width+i]-pixels[j*width+horisontal*(hd+1)-i-1];
						out[d-1]+= tmp;//<0?-tmp:tmp;
					}
				}
				for(int j=hd*vertical; j<(hd+0.5f)*vertical; j++){
					for(int i=0; i<width; i++){
						tmp = pixels[i+j*width]-pixels[i+(vertical*(hd+1)-j-1)*width];
						out[d-1]+= tmp;//<0?-tmp:tmp;
					}
				}
			}	
			out[d-1]/=(height*width*256*256*256.);
			squareSum += out[d-1]*out[d-1];
		}
		squareSum = (float)Math.sqrt(squareSum);
		squareSum = squareSum==0.0f ? 1.0f : squareSum;
		for(int d=1; d<=division; d++){			
			out[d-1]/=squareSum;
			out[d-1] = out[d-1]<0.0f?-out[d-1]:out[d-1]; 
		}
		return out;
	}

	
	@Override
	public int getNumOutput() {		
		return division;
	}

	@Override
	public void setImage(ImageCls image) {
		this.image = image.getImage();
	}
	@Override
	public String getName() { 
		return division+"x"+division+" Symmetry";
	}

	public void setDivision(int div){
		division = div;		
	}
	
	public void setFilters(Filter ... filters) {
		this.filters = filters;
	}
	
	public void unsetFilter(){
		filters = null;
	}
	

}
